﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace JsonDiffDemo.Tool
{
    public class JsonUtilities
    {
        public static string PrettyJsonAndExcludeConfigPaths(string input)
        {
            var formattedJson = string.Empty;

            if (TryGetJsonObject(input, out JObject? jsonObj))
            {
                Console.WriteLine("{");
                Sort(jsonObj!);
                Console.WriteLine("}");

                formattedJson = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
            }

            if (TryGetJsonArray(input, out JArray? jArray))
            {
                Console.WriteLine("[");
                jArray = SortArray(jArray!);
                Console.WriteLine("]");
                formattedJson = JsonConvert.SerializeObject(jArray, Formatting.Indented);
            }

            return formattedJson;
        }

        public static bool TryGetJsonObject(string text, out JObject? jsonObj)
        {
            try
            {
                jsonObj = JObject.Parse(text);
            }
            catch (Exception)
            {
                jsonObj = null;
                return false;
            }

            return true;
        }

        public static bool TryGetJsonArray(string text, out JArray? jsonArr)
        {
            try
            {
                jsonArr = JArray.Parse(text);
            }
            catch (Exception)
            {
                jsonArr = null;
                return false;
            }

            return true;
        }

        public static void Sort(JObject jObj)
        {
            var props = jObj.Properties().ToList();
            //foreach (var prop in props)
            //{
            //    prop.Remove();
            //}

            foreach (var prop in props.OrderBy(p => p.Name))
            {
                //jObj.Add(prop);
                //if(prop.Type == JTokenType.Property)
                //{
                //    Console.WriteLine($"\"{prop.Name}\":{prop.Value},");
                //}

                if (prop.Value is JObject)
                {
                    Console.WriteLine($"\"{prop.Name}\":{prop.Value},");
                    Sort((JObject)prop.Value);
                    continue;
                }

                if (prop.Value is JArray)
                {
                    Console.WriteLine($"\"{prop.Name}\":[");
                    SortArray((JArray)prop.Value);
                    Console.WriteLine($"],");
                    continue;
                }

                Console.WriteLine($"\"{prop.Name}\":{prop.Value},");
            }
        }

        public static JArray SortArray(JArray array)
        {
            if (array.Count == 0 || array.First().Count() == 0)
                return array;

            foreach (var arrayItem in array)
            {
                if (arrayItem.Type == JTokenType.String
                    || arrayItem.Type == JTokenType.Integer
                    || arrayItem.Type == JTokenType.Float
                    || arrayItem.Type == JTokenType.Boolean
                    || arrayItem.Type == JTokenType.Null
                    || arrayItem.Type == JTokenType.Date
                    || arrayItem.Type == JTokenType.Guid
                    || arrayItem.Type == JTokenType.Uri
                    || arrayItem.Type == JTokenType.TimeSpan)
                {
                    Console.WriteLine($"{arrayItem}");
                    continue;
                }

                if (arrayItem is JObject)
                {
                    Console.WriteLine("{");
                    Sort((JObject)arrayItem);
                    Console.WriteLine("},");
                    continue;
                }
            }

            return array;
        }
    }
}
